package net.siufung.web.utils;

import cn.hutool.core.util.StrUtil;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import eu.bitwalker.useragentutils.Version;
import lombok.extern.slf4j.Slf4j;
import net.siufung.core.exception.BizServiceException;
import net.siufung.core.result.Result;
import net.siufung.core.utils.GsonUtil;
import net.siufung.core.utils.StringPool;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.Optional;

/**
 * @author 陈建峰
 * @date 2022/10/3 10:54 下午
 * @since V1.0.0
 */
@Slf4j
public class WebUtil extends org.springframework.web.util.WebUtils {

    /**
     * 获取 HttpServletRequest
     *
     * @return {HttpServletRequest}
     */
    @Nullable
    public static HttpServletRequest getRequest() {
        return Optional.ofNullable(RequestContextHolder.getRequestAttributes())
                .map(x -> (ServletRequestAttributes) x)
                .map(ServletRequestAttributes::getRequest)
                .orElse(null);
    }

    /**
     * 获取 HttpServletResponse
     *
     * @return {HttpServletResponse}
     */
    @Nullable
    public static HttpServletResponse getResponse() {
        return Optional.ofNullable(RequestContextHolder.getRequestAttributes())
                .map(x -> (ServletRequestAttributes) x)
                .map(ServletRequestAttributes::getResponse)
                .orElse(null);
    }

    /**
     * 获取ip
     *
     * @return {String}
     */
    @Nullable
    public static String getIp() {
        return Optional.ofNullable(WebUtil.getRequest())
                .map(WebUtil::getIp)
                .orElse(null);
    }

    public static String getOrigin(){
        HttpServletRequest request = getRequest();
        if(Objects.isNull(request)){
            throw new BizServiceException("request is null");
        }
        return request.getHeader("Origin");
    }

    /**
     * 获取ip
     *
     * @param request HttpServletRequest
     * @return {String}
     */
    @Nullable
    public static String getIp(@Nullable HttpServletRequest request) {
        if(Objects.isNull(request)){
            throw new BizServiceException("request is null");
        }
        String ipAddress = StringPool.EMPTY;
        try {
            ipAddress = request.getHeader("x-forwarded-for");
            if(ipAddress == null || ipAddress.length() == 0 || StringPool.UNKNOWN.equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if(ipAddress == null || ipAddress.length() == 0 || StringPool.UNKNOWN.equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if(ipAddress == null || ipAddress.length() == 0 || StringPool.UNKNOWN.equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getRemoteAddr();
                if(StringPool.LOCAL_IP.equals(ipAddress) || StringPool.NATIVE_IP.equals(ipAddress)){
                    InetAddress inet = InetAddress.getLocalHost();
                    ipAddress = inet.getHostAddress();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return StrUtil.isBlank(ipAddress) ? null : ipAddress.split(StringPool.COMMA)[0];
    }

    /**
     * 获取发起请求的浏览器名称
     * @param request HttpServletRequest
     * @return BrowserName
     */
    public static String getBrowserName(HttpServletRequest request) {
        String header = request.getHeader("User-Agent");
        UserAgent userAgent = UserAgent.parseUserAgentString(header);
        Browser browser = userAgent.getBrowser();
        return browser.getName();
    }

    /**
     * 获取发起请求的浏览器版本号
     * @param request HttpServletRequest
     * @return BrowserVersion
     */
    public static String getBrowserVersion(HttpServletRequest request) {
        String header = request.getHeader("User-Agent");
        UserAgent userAgent = UserAgent.parseUserAgentString(header);
        Browser browser = userAgent.getBrowser();
        Version version = browser.getVersion(header);
        return version.getVersion();
    }

    /**
     * 获取发起请求的操作系统名称
     * @param request 获取发起请求的操作系统名称
     * @return OsName
     */
    public static String getOsName(HttpServletRequest request) {
        String header = request.getHeader("User-Agent");
        UserAgent userAgent = UserAgent.parseUserAgentString(header);
        OperatingSystem operatingSystem = userAgent.getOperatingSystem();
        return operatingSystem.getName();
    }

    /**
     * 返回Result<?>
     * @param response 响应
     * @param result 结果
     */
    public static void writerResult(HttpServletResponse response, Result<?> result) {
        writerJson(response, result);
    }

    /**
     * 返回json
     *
     * @param response HttpServletResponse
     * @param result   结果对象
     */
    public static void writerJson(HttpServletResponse response, Object result) {
        writer(response, GsonUtil.toGsonString(result), MediaType.APPLICATION_JSON_VALUE);
    }

    /**
     * 返回结果
     *
     * @param response HttpServletResponse
     * @param result   结果对象
     * @param contentType   contentType
     */
    public static void writer(HttpServletResponse response, Object result, String contentType) {
        PrintWriter writer = null;
        try {
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "*");
            response.setStatus(HttpStatus.OK.value());
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            response.setContentType(contentType);
            writer = response.getWriter();
            writer.println(result);
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            if(writer != null){
                writer.close();
            }
        }
    }
}
